from datetime import time
from typing import Callable
from vnpy.trader.constant import Interval
from vnpy.app.cta_strategy.base import StopOrderStatus
from vnpy.app.cta_strategy import (
    CtaTemplate,
    StopOrder,
    TickData,
    BarData,
    TradeData,
    OrderData,
    BarGenerator,
    ArrayManager,
)

class RBreakerReverseStrategy(CtaTemplate):
    """"""
    author = "KeKe"
    
    setup_coef = 0.25
    enter_coef_a = 1.07
    enter_coef_b = 0.07
    fixed_size = 1
    donchian_window = 30
    
    trailing_long = 0.4
    trailing_short = 0.4
    multiplier = 1
    
    sell_setup = 0  # 观察卖出价
    sell_enter = 0  # 反转卖出价
    buy_enter = 0   # 反转买入价
    buy_setup = 0   # 观察买入价
    
    intra_trade_high = 0
    intra_trade_low = 0
    
    day_high = 0
    day_open = 0
    day_close = 0
    day_low = 0
    tend_high = 0
    tend_low = 0
    
    exit_time = time(hour=14, minute=55)
    
    parameters = ["setup_coef",  "enter_coef_a", "enter_coef_b", "fixed_size", "donchian_window","trailing_long","trailing_short"]
    variables = ["sell_setup", "sell_enter", "buy_enter", "buy_setup"]
    # variables = []
    
    def __init__(self, cta_engine, strategy_name, vt_symbol, setting):
        """"""
        super(RBreakerReverseStrategy, self).__init__(
            cta_engine, strategy_name, vt_symbol, setting
        )
        
        self.bg = BarGenerator(self.on_bar)
        self.am = ArrayManager()
        self.bars = []

        self.buy_vt_orderids = []
        self.sell_vt_orderids = []
        self.short_vt_orderids = []
        self.cover_vt_orderids = []

        self.buy_price = 0
        self.sell_price = 0
        self.short_price = 0
        self.cover_price = 0
        
    def on_init(self):
        """
        Callback when strategy is inited.
        """
        self.write_log("策略初始化")
        self.load_bar(10)
        
    def on_start(self):
        """
        Callback when strategy is started.
        """
        self.write_log("策略启动")
        
    def on_stop(self):
        """
        Callback when strategy is stopped.
        """
        self.write_log("策略停止")
        
    def on_tick(self, tick: TickData):
        """
        Callback of new tick data update.
        """
        self.bg.update_tick(tick)
        
    def on_bar(self, bar: BarData):
        """
        Callback of new bar data update.
        """
        self.cancel_all()
        
        am = self.am
        am.update_bar(bar)
        if not am.inited:
            return
            
        self.bars.append(bar)
        if len(self.bars) <= 2:
            return
        else:
            self.bars.pop(0)
        last_bar = self.bars[-2]
        
        # New Day
        if last_bar.datetime.date() != bar.datetime.date():
            if self.day_open:
                
                self.buy_setup = self.day_low - self.setup_coef * (self.day_high - self.day_close)  # 观察买入价
                self.sell_setup = self.day_high + self.setup_coef * (self.day_close - self.day_low)  # 观察卖出价
                
                self.buy_enter = (self.enter_coef_a / 2) * (self.day_high + self.day_low) - self.enter_coef_b * self.day_high  # 反转买入价
                self.sell_enter = (self.enter_coef_a / 2) * (self.day_high + self.day_low) - self.enter_coef_b * self.day_low  # 反转卖出价
                
            self.day_open = bar.open_price
            self.day_high = bar.high_price
            self.day_close = bar.close_price
            self.day_low = bar.low_price
            
        # Today
        else:
            self.day_high = max(self.day_high, bar.high_price)
            self.day_low = min(self.day_low, bar.low_price)
            self.day_close = bar.close_price
            
        if not self.sell_setup:
            return

        self.tend_high, self.tend_low = am.donchian(self.donchian_window)
        
        if bar.datetime.time() < self.exit_time:
            
            if self.pos == 0:
                self.intra_trade_low = bar.low_price
                self.intra_trade_high = bar.high_price
                
                if self.tend_high > self.sell_setup:
                    self.short(self.sell_enter, self.multiplier * self.fixed_size, stop=True)

                    # self.buy_price = 0
                    # self.sell_price = 0
                    # self.short_price = self.sell_enter
                    # self.cover_price = 0
                    
                elif self.tend_low < self.buy_setup:
                    self.buy(self.buy_enter, self.multiplier * self.fixed_size, stop=True)

                    # self.buy_price = self.buy_enter
                    # self.sell_price = 0
                    # self.short_price = 0
                    # self.cover_price = 0
                    
            elif self.pos > 0:
                self.intra_trade_high = max(self.intra_trade_high, bar.high_price)
                long_stop = self.intra_trade_high * (1 - self.trailing_long / 100)
                self.sell(long_stop, abs(self.pos), stop=True)

                # self.buy_price = 0
                # self.sell_price = long_stop
                # self.short_price = 0
                # self.cover_price = 0
                
            elif self.pos < 0:
                self.intra_trade_low = min(self.intra_trade_low, bar.low_price)
                short_stop = self.intra_trade_low * (1 + self.trailing_short / 100)
                self.cover(short_stop, abs(self.pos), stop=True)

                # self.buy_price = 0
                # self.sell_price = 0
                # self.short_price = 0
                # self.cover_price = short_stop
                
        # Close existing position
        else:
            if self.pos > 0:
                self.sell(bar.close_price * 0.99, abs(self.pos))
                # self.buy_price = 0
                # self.sell_price = bar.close_price * 0.99
                # self.short_price = 0
                # self.cover_price = 0

            elif self.pos < 0:
                self.cover(bar.close_price * 1.01, abs(self.pos))
                # self.buy_price = 0
                # self.sell_price = 0
                # self.short_price = 0
                # self.cover_price = bar.close_price * 1.01

        # # 根据信号执行挂撤交易
        # if self.pos == 0:
        #     # 检查之前委托都已经结束
        #     if not self.buy_vt_orderids:
        #         # 检查存在信号
        #         if self.buy_price:
        #             self.buy_vt_orderids = self.buy(self.buy_price, self.fixed_size, True, True)
        #             self.buy_price = 0      # 执行需要清空信号
        #     else:
        #         # 遍历委托号列表撤单
        #         for vt_orderid in self.buy_vt_orderids:
        #             self.cancel_order(vt_orderid)
            
        #     if not self.short_vt_orderids:
        #         if self.short_price:
        #             self.short_vt_orderids = self.short(self.short_price, self.fixed_size, True, True)
        #             self.short_price = 0
        #     else:
        #         for vt_orderid in self.short_vt_orderids:
        #             self.cancel_order(vt_orderid)
        # elif self.pos > 0:
        #     if not self.sell_vt_orderids:
        #         if self.sell_price:
        #             self.sell_vt_orderids = self.sell(self.sell_price, abs(self.pos), True, True)
        #             self.sell_price = 0
        #     else:
        #         for vt_orderid in self.sell_vt_orderids:
        #             self.cancel_order(vt_orderid)
        # else:
        #     if not self.cover_vt_orderids:
        #         if self.cover_price:
        #             self.cover_vt_orderids = self.cover(self.cover_price, abs(self.pos), True, True)
        #             self.cover_price = 0
        #     else:
        #         for vt_orderid in self.cover_vt_orderids:
        #             self.cancel_order(vt_orderid)
                
        self.put_event()
                
    def on_order(self, order: OrderData):
        """
        Callback of new order data update.
        """
        pass
    
    def on_trade(self, trade: TradeData):
        """
        Callback of new trade data update.
        """
        self.put_event()
        
    def on_stop_order(self, stop_order: StopOrder):
        """
        Callback of stop order update.
        """
        # # 只处理撤销或者触发的停止单委托
        # if stop_order.status == StopOrderStatus.WAITING:
        #     return

        # # 移除已经结束的停止单委托号
        # for buf_orderids in [
        #     self.buy_vt_orderids,
        #     self.sell_vt_orderids,
        #     self.short_vt_orderids,
        #     self.cover_vt_orderids
        # ]:
        #     if stop_order.stop_orderid in buf_orderids:
        #         buf_orderids.remove(stop_order.stop_orderid)
        
        # # 发出新的委托
        # if self.pos == 0:
        #     if not self.buy_vt_orderids:
        #         if self.buy_price:
        #             self.buy_vt_orderids = self.buy(self.buy_price, self.fixed_size, True, True)
        #             self.buy_price = 0
            
        #     if not self.short_vt_orderids:
        #         if self.short_price:
        #             self.short_vt_orderids = self.short(self.short_price, self.fixed_size, True, True)
        #             self.short_price = 0
            
        # elif self.pos > 0:
        #     if not self.sell_vt_orderids:
        #         if not self.sell_price:
        #             self.sell_vt_orderids = self.sell(self.sell_price, abs(self.pos), True, True)
        #             self.sell_price = 0
            
        # else:
        #     if not self.cover_vt_orderids:
        #         if not self.cover_price:
        #             self.cover_vt_orderids = self.cover(self.cover_price, abs(self.pos), True, True)
        #             self.cover_price = 0
        pass